/* Copyright (c) 2025 Beijing Semidrive Technology Corporation
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/** ************************************************************************************************
 *  @file     Mbox.h                                                                          *
 *  @brief    This file contains interface header for MAILBOX SSDK driver                          *
 *                                                                                                 *
 **************************************************************************************************/
#ifndef MBOX_H
#define MBOX_H

#include "lld_platform.h"
#include "Mbox_Ip.h"

/* max supported mailbox channel */
#define SDRV_MBOX_CHN_NUM           8U

#define SDRV_MBOX_SHORT_MSG_LEN     6U
#define SDRV_MBOX_MSG_ALIGN_BYTES   2U
#define SDRV_MBOX_BUF_ALIGN_BYTES   64U
#define SDRV_MBOX_BUF_LEN_MASK      0x400U

#define SDRV_MBOX_NO_WAIT           0U
#define SDRV_MBOX_WAIT_FOREVER      0xffffffffU

/* if share memory is normal type, driver needs to flush or invalidate cache,
 * If you use MPU to set the shared memory property to no-cache,
 * you do not need to enable this macro.
 */
#if !defined(CONFIG_MBOX_CACHE_MANAGED_BY_DRVIVER)
#define SDRV_MBOX_MANAGE_CACHE      1U
#else
#define SDRV_MBOX_MANAGE_CACHE      CONFIG_MBOX_CACHE_MANAGED_BY_DRVIVER
#endif

/**
 * @brief mailbox status error code.
 */
enum sdrv_mbox_error
{
#if (defined(CFG_PLATFORM_MCAL))
    /* success. */
    SDRV_MBOX_STATUS_OK = 0,
    /* Invalid mailbox master id. */
    SDRV_MBOX_STATUS_INVALID_MASTERID,
    /* Invalid mailbox message Length. */
    SDRV_MBOX_STATUS_LENGTH_ERROR,
    /* No mailbox channel. */
    SDRV_MBOX_STATUS_NO_CHANNEL,
    /* No mailbox message buffer. */
    SDRV_MBOX_STATUS_NO_MSG_BUFFER,
    /* mailbox timeout error. */
    SDRV_MBOX_STATUS_TIMEOUT,
    /* mailbox invalid param. */
    SDRV_MBOX_STATUS_INVALID_PARAM,
    /* mailbox status error. */
    SDRV_MBOX_STATUS_ERROR,
#else
    /* success. */
    SDRV_MBOX_STATUS_OK = SDRV_STATUS_OK,
    /* Invalid mailbox master id. */
    SDRV_MBOX_STATUS_INVALID_MASTERID = SDRV_ERROR_STATUS(SDRV_STATUS_GROUP_MBOX, 0),
    /* Invalid mailbox message Length. */
    SDRV_MBOX_STATUS_LENGTH_ERROR = SDRV_ERROR_STATUS(SDRV_STATUS_GROUP_MBOX, 1),
    /* No mailbox channel. */
    SDRV_MBOX_STATUS_NO_CHANNEL = SDRV_ERROR_STATUS(SDRV_STATUS_GROUP_MBOX, 2),
    /* No mailbox message buffer. */
    SDRV_MBOX_STATUS_NO_MSG_BUFFER = SDRV_ERROR_STATUS(SDRV_STATUS_GROUP_MBOX, 3),
    /* mailbox timeout error. */
    SDRV_MBOX_STATUS_TIMEOUT = SDRV_ERROR_STATUS(SDRV_STATUS_GROUP_MBOX, 4),
    /* mailbox invalid param. */
    SDRV_MBOX_STATUS_INVALID_PARAM = SDRV_ERROR_STATUS(SDRV_STATUS_GROUP_MBOX, 5),
    /* mailbox status error. */
    SDRV_MBOX_STATUS_ERROR = SDRV_ERROR_STATUS(SDRV_STATUS_GROUP_MBOX, 6),
#endif
};

/**
 * @brief mailbox channel id
 *
 * Mbox channel id is used to define different mbox message types,
 * especially for the frequent used messages, such as rpmsg or power-manage.
 * Raw data (MBOX_CHN_ID_RAW) is usually chosen for the messages without any type.
 *
 */
typedef enum {
    MBOX_CHN_ID_HSM      = 0x0U,  /* HSM message */
    MBOX_CHN_ID_RAW      = 0x1U,  /* Raw data */
    MBOX_CHN_ID_PM       = 0x2U,  /* Power-manage data */
    /* PRQA S 1535 1 */
} sdrv_mbox_channel_id_t;

/**
 * @brief mailbox rx callback
 */
typedef int32_t (*sdrv_mbox_rxcallback)(void *arg, uint16_t proc_id, uint8_t *data, uint32_t len);
/**
 * @brief mailbox wakeup callback
 */
typedef int32_t (*sdrv_mbox_wakeup_callback)(void *arg, uint32_t src, uint32_t msg);

/**
 * @brief mailbox channel transfer configuration
 */
typedef struct sdrv_mbox_chan_req {
    uint32_t                rproc;
    uint16_t                channel_id;
} sdrv_mbox_chan_req_t;

/**
 * @brief mailbox device
 */
struct sdrv_mbox_dev;

/**
 * @brief mailbox configurations
 */
typedef struct sdrv_mbox_config {
    uint32_t                base;              /* mbox register base address */
    uint32_t                mem_base;          /* mbox share memory base address */
    int32_t                 irq;               /* mbox irq number */
    int32_t                 wakeup_irq;        /* mbox wakeup irq number */
    uint8_t                 ack_mode;          /* mbox interrupt triggered or not when ack */
} sdrv_mbox_config_t;

/**
 * @brief mailbox channel private data
 */
typedef struct sdrv_mbox_chan {
    struct sdrv_mbox_dev         *dev;                /* mbox device */
    uint16_t                     channel_id;          /* mbox channel id */
    uint8_t                      used;                /* mbox channel used flag */
    uint8_t                      buf_mask;            /* mbox message buffer mask */
    uint32_t                     rproc;               /* mbox remote processor mask */
    sdrv_mbox_rxcallback         callback;            /* mbox channel callback function */
    void                         *arg;                /* mbox channel argument */
} sdrv_mbox_chan_t;

/**
 * @brief mailbox device
 */
typedef struct sdrv_mbox_dev {
    uint32_t                base;                     /* mbox register base address */
    uint32_t                mem_base;                 /* mbox share memory base address */
    int32_t                 irq;                      /* mbox irq number */
    int32_t                 wakeup_irq;               /* mbox wakeup irq number */
    uint8_t                 chan_num;                 /* mbox max channel number */
    uint8_t                 ack_mode;                 /* mbox interrupt triggered or not when ack */
    sdrv_mbox_chan_t        chan[SDRV_MBOX_CHN_NUM];  /* mbox channel */
    Mbox_Ip_ChnCfgType      mbox_chan[MBOX_MSG_NUM];  /* mbox send channel configuration */
    Mbox_Ip_ChnCfgType      mbox_rxchan;              /* mbox receive channel configuration */
    Mbox_Ip_ChnCfgType      mbox_wakeupchan;          /* mbox wakeup channel configuration */
    uint32_t                msg_bitmap;               /* mbox message used flag */
    uint32_t                buf_bitmap;               /* mbox share memory used flag */
    sdrv_mbox_wakeup_callback wakeup_callback;        /* mbox wakeup callback function */
    void                    *wakeup_arg;              /* mbox wakeup argument */
    void                    *priv;                    /* mbox private data (reserved for lock) */
} sdrv_mbox_t;

/**
 * @brief allocate availible buffer.
 *
 * The function is used to allocate the buffers, user will fill message data
 * to the buffers firstly. Then, sdrv_mbox_send is called to send message data.
 *
 * @param[in] chan the structure pointer of the abstract mailbox channel.
 * @param[in] len the length of the data to be sent (aliged with SDRV_MBOX_BUF_ALIGN_BYTES bytes).
 * @return the address of the buffer.
 */
uint8_t *sdrv_mbox_alloc_buffer(sdrv_mbox_chan_t *sdrv_chan, uint32_t len);

/**
 * @brief release the occupied message buffer.
 *
 * @param[in] sdrv_mbox the structure pointer of the abstract mailbox device.
 * @param[in] buf_id the message buffer id.
 */
void sdrv_mbox_free_buffer(sdrv_mbox_chan_t *sdrv_chan);

/**
 * @brief send the short message.
 *
 * The function is used to send short message data.
 * The data length is not more than 6 bytes.
 * The message data will be stored in the TMH1/2 register.
 *
 * @param[in] chan the structure pointer of the abstract mailbox channel.
 * @param[in] data the pointer of the data to be sent.
 * @param[in] len the length of the data to be sent.
 * @param[in] timeout wait timeout (ms).
 * @return SDRV_MBOX_STATUS_OK if success, otherwise return error status.
 */
lld_status_t sdrv_mbox_send_short_msg(sdrv_mbox_chan_t *sdrv_chan, uint8_t *data, uint32_t len,
                                  uint32_t timeout);
/**
 * @brief send long message without copy.
 *
 * The function is used to send message data without copying data to the buffers.
 * The function is combined with sdrv_mbox_alloc_buffer which have been allocated the buffers.
 * In addition, user can select a proper memory for message transmission,
 * but you need to pay attention to the cache for the memory.
 *
 * @param[in] chan the structure pointer of the abstract mailbox channel.
 * @param[in] data the pointer of the data to be sent.
 * @param[in] len the length of the data to be sent (aliged with SDRV_MBOX_BUF_ALIGN_BYTES bytes).
 * @param[in] timeout wait timeout (ms).
 * @return SDRV_MBOX_STATUS_OK if success, otherwise return error status.
 */
lld_status_t sdrv_mbox_send(sdrv_mbox_chan_t *sdrv_chan, uint8_t *data, uint32_t len,
                        uint32_t timeout);

/**
 * @brief request available mailbox channel.
 *
 * @param[in] dev the structure pointer of the abstract mailbox device.
 * @param[in] chan_req mailbox channel parameters.
 * @return the structure pointer of the abstract mailbox channel.
 */
sdrv_mbox_chan_t *sdrv_mbox_request_channel(sdrv_mbox_t *dev, sdrv_mbox_chan_req_t *chan_req);

/**
 * @brief release mailbox channel.
 *
 * @param[in] chan the structure pointer of the abstract mailbox channel.
 * @return SDRV_MBOX_STATUS_OK if success, SDRV_MBOX_STATUS_INVALID_PARAM if chan is null.
 */
lld_status_t sdrv_mbox_release_channel(sdrv_mbox_chan_t *chan);

/**
 * @brief receive the message.
 *
 * @param[in] dev the structure pointer of the abstract mailbox device.
 */
void sdrv_mbox_recv_msg(const sdrv_mbox_t *dev);

/**
 * @brief mailbox wakeup.
 *
 * @param[in] sdrv_chan the structure pointer of the abstract mailbox channel.
 * @param[in] wakeup_msg wakeup message.
 * @param[in] timeout wait timeout (ms).
 * @return SDRV_MBOX_STATUS_OK if success, otherwise return error status.
 */
lld_status_t sdrv_mbox_wakeup(sdrv_mbox_chan_t *sdrv_chan, uint32_t wakeup_msg, uint32_t timeout);

/**
 * @brief set mailbox callback function.
 *
 * @param[in] chan the structure pointer of the abstract mailbox channel.
 * @param[in] callback the callback handler.
 * @param[in] arg the callback parameter.
 * @return SDRV_MBOX_STATUS_OK if success, SDRV_MBOX_STATUS_INVALID_PARAM if chan or callback is null.
 */
lld_status_t sdrv_mbox_set_callback(sdrv_mbox_chan_t *chan, sdrv_mbox_rxcallback callback, void *arg);

/**
 * @brief set mailbox wakeup callback function.
 *
 * @param[in] chan the structure pointer of the abstract mailbox channel.
 * @param[in] callback the wakeup callback handler.
 * @param[in] arg the callback parameter.
 * @return SDRV_MBOX_STATUS_OK if success, SDRV_MBOX_STATUS_INVALID_PARAM if chan or callback is null.
 */
lld_status_t sdrv_mbox_set_wakeup_callback(sdrv_mbox_t *dev, sdrv_mbox_wakeup_callback callback, void *arg);

/**
 * @brief config mailbox device.
 *
 * @param[in] dev the structure pointer of the abstract mailbox device.
 * @param[in] cfg the configuration of the mailbox device.
 * @return SDRV_MBOX_STATUS_OK if success,otherwise return error code.
 */
lld_status_t sdrv_mbox_early_init(sdrv_mbox_t *dev, const sdrv_mbox_config_t *cfg);

/**
 * @brief initialize mailbox device.
 *
 * @param[in] dev the structure pointer of the abstract mailbox device.
 * @param[in] cfg the configuration of the mailbox device.
 * @return SDRV_MBOX_STATUS_OK if success,otherwise return error code.
 */
lld_status_t sdrv_mbox_init(sdrv_mbox_t *dev, const sdrv_mbox_config_t *cfg);

/**
 * @brief enable/disable mailbox interrupt.
 *
 * @param[in] dev the structure pointer of the abstract mailbox device.
 * @param[in] en 1:enable,0:disable.
 * @return SDRV_MBOX_STATUS_OK if success,otherwise return error code.
 */
lld_status_t sdrv_mbox_enable_irq(sdrv_mbox_t *dev, bool en);

/**
 * @brief enable/disable mailbox wakeup interrupt.
 *
 * @param[in] dev the structure pointer of the abstract mailbox device.
 * @param[in] en 1:enable,0:disable.
 * @return SDRV_MBOX_STATUS_OK if success,otherwise return error code.
 */
lld_status_t sdrv_mbox_enable_wakeup_irq(sdrv_mbox_t *dev, bool en);

/**
 * @brief get the master id of mailbox.
 *
 * @param[in] proc_id the mailbox port number.
 */
uint16_t sdrv_mbox_get_master_id(uint16_t proc_id);

/**
 * @brief mailbox interrupt handler.
 *
 * @param[in] irq the irq number.
 * @param[in] arg the parameter of the interrupt handler.
 * @return SDRV_MBOX_STATUS_OK if success.
 *         SDRV_MBOX_STATUS_INVALID_PARAM if arg is NULL.
 */
lld_int_t sdrv_mbox_irq_handler(uint32_t irq, void *arg);

/**
 * @brief mailbox wakeup interrupt handler.
 *
 * @param[in] irq the irq number.
 * @param[in] arg the parameter of the interrupt handler.
 * @return SDRV_MBOX_STATUS_OK if success.
 *         SDRV_MBOX_STATUS_INVALID_PARAM if arg is NULL.
 */
lld_int_t sdrv_mbox_wakeup_irq_handler(uint32_t irq, void *arg);

/**
 * @brief set the master id of mailbox.
 *
 * @param[in] base the base physical address.
 */
void sdrv_mbox_set_master_id(uint32_t base);

/**
 * @brief check the master id of mailbox is valid.
 *
 * @param[in] base the base physical address.
 * @return SDRV_MBOX_STATUS_OK if success,otherwise return error code.
 */
lld_status_t sdrv_mbox_check_master_id(uint32_t base);

#endif/* MBOX_H */
/* End of file */
